package net.web.inst.service.impl;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import net.esj.basic.dao.jdbc.JdbcDao;
import net.esj.basic.dao.querybuilder.QueryBuilder;
import net.esj.basic.exception.MelonException;
import net.esj.basic.service.impl.DefaultServiceImpl;
import net.esj.basic.utils.Pagination;
import net.esj.basic.utils.StringUtils;
import net.esj.basic.utils.Validators;
import net.melon.article.pojo.Article;
import net.melon.cata.inst.eg.region.Region;
import net.melon.jdbc.core.RowMapper;
import net.melon.page.inst.service.ModuleService;
import net.melon.page.pojo.ModuleLink;
import net.melon.product.inst.hibernate.mapping.dto.ProductMapRow;
import net.melon.product.inst.service.ProductService;
import net.melon.product.inst.service.impl.ClassifyCacheProxy;
import net.melon.product.inst.service.impl.SpecificationsValueCacheProxy;
import net.melon.product.pojo.Product;
import net.melon.product.pojo.Product.PRODUCT_ENABLE;
import net.melon.product.pojo.ProductClassify;
import net.melon.product.pojo.ProductImage;
import net.melon.product.pojo.ProductSpecificationsLink;
import net.melon.product.pojo.ProductSpecificationsValue;
import net.melon.stock.inst.service.StockService;
import net.melon.stock.pojo.Stock;
import net.melon.uploader.Uploader;
import net.web.dto.BaseParam;
import net.web.dto.City;
import net.web.dto.ClassifyDto;
import net.web.dto.ParamArticle;
import net.web.dto.ParamDto;
import net.web.dto.ParameterDto;
import net.web.dto.ProductDetail;
import net.web.dto.ProductDto;
import net.web.dto.ProductSpecificationsLinkDto;
import net.web.dto.UnicodeParamDto;
import net.web.inst.service.WebService;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.stereotype.Service;

@Service
public class WebServiceImpl extends DefaultServiceImpl implements WebService {
	
	@Resource
	private ClassifyCacheProxy classifyCacheProxy;
	
	@Resource
	private ProductService productService;
	
	@Resource
	private StockService stockService;
	
	@Resource
	private ModuleService moduleService;
	
	@Resource
	private SpecificationsValueCacheProxy specificationsValueCacheProxy;
	
	//private static String PRODUCT_PAGE = "SELECT p.* , pc.name c_name FROM ML_PRODUCT_CLASSIFY pc,ML_PRODUCT p WHERE p.CLASSIFY_ID = pc.ID AND p.MARKET_ENABLE=" + PRODUCT_ENABLE.YES.getMarketEnable();
	
	private static String PRODUCT_PAGE = "SELECT p.*,c.NAME c_name FROM stock s LEFT JOIN ML_PRODUCT p ON p.ID = s.PRODUCT LEFT JOIN ML_PRODUCT_CLASSIFY c ON p.CLASSIFY_ID = c.ID WHERE s.COUNT>0 AND p.STATE=1 AND p.MARKET_ENABLE = "+PRODUCT_ENABLE.YES.getMarketEnable();
	
	@Override
	public Pagination<Product> productPage(Integer page, Integer rp, Long manufacturers,Long brands, Long cars, Double price1, Double price2, Integer orderBy1,Integer orderBy2, String searchStr, Long regionId) {
		StringBuffer sb = new StringBuffer(PRODUCT_PAGE);
		if(regionId!=null){
			sb.append(" AND s.REGION = '"+regionId+"'");
		}
		List<Long> classifyIds = getClassifyIds(searchStr,manufacturers,brands,cars);
		Pagination<Product> pagination = new Pagination<Product>(rp, page, Product.class);
		String classifyStr = "";
		for(Long classifyId : classifyIds){
			classifyStr += "'"+classifyId+"',"; 
		}
		if(StringUtils.hasText(classifyStr)){
			classifyStr = classifyStr.substring(0, classifyStr.length()-1); 
			if(StringUtils.hasText(searchStr)){
				sb.append(" AND ( p.CLASSIFY_ID in ("+classifyStr+") OR p.NAME LIKE '%"+searchStr+"%' ) ");
			}else{
				sb.append(" AND p.CLASSIFY_ID in ("+classifyStr+")");
			}
		}else if(StringUtils.hasText(searchStr)){
			sb.append(" AND (p.CLASSIFY_ID in ('') OR p.NAME LIKE '%"+searchStr+"%' ) ");
		}
		
		if(price1!=null && price2!=null && price2!=0 && price1!=0 && price1>price2){
			double p = price2;
			price2 = price1;
			price1 = p;
		}
		if(price1!=null && price1!=0){
			sb.append(" AND p.PRICE >= "+price1 );
		}
		if(price2!=null && price2!=0){
			sb.append(" AND p.PRICE <="+price2);
		}
		if(orderBy1!=null && orderBy1==1){
			if(orderBy2!=null && orderBy2==1){
				sb.append(" ORDER BY p.PRICE ASC , p.MARKET_TIME ASC");
			}else if(orderBy2!=null && orderBy2==2){
				sb.append(" ORDER BY p.MARKET_TIME DESC ,  p.PRICE ASC");
			}
		}else if(orderBy1!=null && orderBy1==2){
			if(orderBy2!=null && orderBy2==1){
				sb.append(" ORDER BY p.PRICE DESC , p.MARKET_TIME ASC ");
			}else if(orderBy2!=null && orderBy2==2){
				sb.append(" ORDER BY p.PRICE DESC , p.MARKET_TIME DESC ");
			}
		}
		pagination = ((JdbcDao)dao).queryPage(sb.toString(), new ProductMapRow(), pagination,"");
		for(Product product : pagination.getRows()){
			List<ProductImage> images = productService.getProductImageList(product.getId());
			product.getImages().addAll(images);
		}
		return pagination;
	}
	
	/*@Override
	public Pagination<Product> productPage(int page, int rp, Long manufacturers,Long brands, Long cars, double price1, double price2, int orderBy1,
			int orderBy2) {
		List<Long> classifyIds = getClassifyIds(manufacturers,brands,cars);
		Pagination<Product> pagination = new Pagination<Product>(rp, page, Product.class);
		if(!Validators.isEmpty(classifyIds)){
			pagination.getQueryBuilder().in("classifyId", classifyIds);
		}
		pagination.getQueryBuilder().eq("marketEnable", PRODUCT_ENABLE.YES.getMarketEnable());
		if(price1>price2){
			double p = price2;
			price2 = price1;
			price1 = p;
		}
		if(price2!=0){
			pagination.getQueryBuilder().ge("price", price1).le("price", price2);
		}
		if(orderBy1==1){
			pagination.getQueryBuilder().OrderByAsc("price");
		}else if(orderBy1==2){
			pagination.getQueryBuilder().OrderByDesc("price");
		}
		if(orderBy2==1){
			pagination.getQueryBuilder().OrderByAsc("marketTime");
		}else if(orderBy2==2){
			pagination.getQueryBuilder().OrderByDesc("marketTime");
		}
		pagination = queryPageByQueryBuilder(pagination);
		for(Product product : pagination.getRows()){
			List<ProductImage> images = productService.getProductImageList(product.getId());
			product.getImages().addAll(images);
		}
		return pagination;
	}*/

	private List<Long> getClassifyIds(String searchStr, Long manufacturers, Long brands, Long cars) {
		List<Long> ids = new ArrayList<Long>();
		if(StringUtils.hasLength(searchStr)){
			List<ProductClassify> list  = classifyCacheProxy.getProductClassifyList(new Object[]{1,0});
			for(ProductClassify pc : list){
				if(pc.getName().indexOf(searchStr)!=-1){
					ids.add(pc.getId());
				}
			}
		}else{
			if(cars!=null || brands!=null || manufacturers!=null){
				if(cars!=null){
					ids.add(cars);
					return ids;
				}else if(brands!=null){
					ids = getChildren(brands,2);
				}else if(manufacturers!=null){
					ids = getChildren(manufacturers,1);
				}
			}
		}
		return ids;
	}

	private List<Long> getChildren(Long id,int level) {
		List<ProductClassify> list  = classifyCacheProxy.getProductClassifyList(new Object[]{1,0});
		List<Long> ids = new ArrayList<Long>();
		for(ProductClassify pc : list){
			if(pc.getParent()!=null && pc.getParent().getId() == id){
				ids.add(pc.getId());
				if(level==1){
					ids.addAll(getChildren(pc.getId(), 2));
				}
			}
		}
		return ids;
	}

	@Override
	public ProductDetail getProductDetail(String id) throws MelonException,
			Exception {
		Product product = productService.getProduct(id, true, true, false, true, false);
		ProductDetail dto = new ProductDetail();
		Map<Long,ProductSpecificationsValue> specifications = specificationsValueCacheProxy.getList();
		Map<Long,ParameterDto> parameterMap = new HashMap<Long, ParameterDto>();
		for(Long valueId : specifications.keySet()){
			ProductSpecificationsValue productSpecificationsValue = specifications.get(valueId);
			if(productSpecificationsValue.getSpecifications().getId()==3){
				//parameterMap.put(valueId,specifications.get(valueId));
				parameterMap.put(valueId,new ParameterDto(productSpecificationsValue.getId(),"",productSpecificationsValue.getValue()));
			}
		}
		for(ProductSpecificationsLink link : product.getSpecifications()){
			ProductSpecificationsValue productSpecificationsValue = specifications.get(link.getSpecificationsValue());
			if(link.getSpecificationsId()==1){
				dto.getColourList().add(new ProductSpecificationsLinkDto(link.getValue(),productSpecificationsValue.getValue(),Uploader.getDownUrl(ProductSpecificationsValue.ICON_DIR) + productSpecificationsValue.getImage()));
			}/*else if(link.getSpecificationsId()==2){
				dto.getConfigList().add(new ProductSpecificationsLinkDto(link.getValue(),productSpecificationsValue.getValue(),productSpecificationsValue.getImage()));
			}*/else if(link.getSpecificationsId()==3){
				ParameterDto parameterDto = parameterMap.get(link.getSpecificationsValue());  
				parameterDto.setValue(link.getValue());
				parameterMap.put(link.getSpecificationsValue(), parameterDto);
			}
		}
		List<ParameterDto> parameterDtos = new ArrayList<ParameterDto>(parameterMap.values());
		Collections.sort(parameterDtos, new Comparator<ParameterDto>(){
			@Override
			public int compare(ParameterDto o1,
					ParameterDto o2) {
				if(o1.getId()>o2.getId()){
					return 1;
				}else if(o1.getId()<o2.getId()){
					return -1;
				}
				return 0;
			}
			
		});
		dto.setParameterList(parameterDtos);
		ProductDto productDto = new ProductDto();
		BeanUtils.copyProperties(productDto, product);
		if(!Validators.isEmpty(product.getImages())){
			productDto.setIcon(Uploader.getDownUrl(Product.ICON_SUB_DIR) + product.getImages().get(0).getIcon());
		}else{
			productDto.setIcon(Uploader.getDownUrl(Product.ICON_SUB_DIR));
		}
		if(product.getClassify()!=null){
			List<ProductClassify> classifys = classifyCacheProxy.getClassifyParents(product.getClassify());
			ClassifyDto classifyNames = new ClassifyDto();
			switch (classifys.size()) {
			case 1:
				BaseParam param = new BaseParam(String.valueOf(classifys.get(0).getId()), classifys.get(0).getName());
				classifyNames.setSeries(param);
				break;
			case 2:
				param = new BaseParam(String.valueOf(classifys.get(1).getId()), classifys.get(1).getName());
				classifyNames.setBrand(param);
				param = new BaseParam(String.valueOf(classifys.get(0).getId()), classifys.get(0).getName());
				classifyNames.setClassify(param);
				break;
			case 3:
				param = new BaseParam(String.valueOf(classifys.get(2).getId()), classifys.get(2).getName());
				classifyNames.setSeries(param);
				param = new BaseParam(String.valueOf(classifys.get(1).getId()), classifys.get(1).getName());
				classifyNames.setBrand(param);
				param = new BaseParam(String.valueOf(classifys.get(0).getId()), classifys.get(0).getName());
				classifyNames.setClassify(param);
				break;
			default:
				break;
			}
			productDto.setClassifyName(classifyNames);
		}
		dto.setProductDto(productDto);
		dto.setRegionNames(getRegionNames(id));
		dto.setSameModel(getSameModel(product.getClassifyId()));
		for(ProductImage image : product.getImages()){
			dto.getImages().add(new BaseParam(String.valueOf(image.getId()), Uploader.getDownUrl(Product.ICON_SUB_DIR) + image.getIcon()));
		}
		return dto;
	}

	private List<BaseParam> getSameModel(Long id) {
		Map<String, String> map = new HashMap<String, String>();
		List<Product> list = productService.getProductByClassifyAndStock(id, true);
		for(Product product : list){
			map.put(product.getId(), product.getName());
		}
		List<BaseParam> params = new ArrayList<BaseParam>();
		for(String s : map.keySet()){
			params.add(new BaseParam(s,map.get(s)));
		}
		return params;
	}

	private List<BaseParam> getRegionNames(String id) {
		Map<Integer, Region> map = new HashMap<Integer, Region>();
		List<Stock> list = stockService.getStockListByProductId(id);
		if(!Validators.isEmpty(list)){
			for(Stock stock : list){
				map.put(stock.getId(), get(Long.valueOf(stock.getRegionId()), Region.class));
			}
		}
		List<BaseParam> params = new ArrayList<BaseParam>();
		for(Region region : map.values()){
			params.add(new BaseParam(region.getId().toString(),region.getName()));
		}
		return params;
	}

	@Override
	public List<ParamDto> getAdvList() {
		List<ModuleLink> list = moduleService.getModuleLinkList(1,0);
		List<ParamDto> dtos = new ArrayList<ParamDto>();
		for(ModuleLink link : list){
			ParamDto dto = new ParamDto(link);
			dto.setValue(Uploader.getDownUrl(ModuleLink.MODULE_LINK_ICON) + dto.getValue());
			dtos.add(dto);
		}
		return dtos;
	}

	@Override
	public  List<UnicodeParamDto> getBrandList() {
		List<ProductClassify> classfies = classifyCacheProxy.getProductClassifyList(new Object[]{1,0});
		List<UnicodeParamDto> dtos = new ArrayList<UnicodeParamDto>();
		for(ProductClassify pc : classfies){
			if(pc.getLevel()==2){
				try {
					dtos.add(new UnicodeParamDto(String.valueOf(pc.getId()),pc.getName(),URLEncoder.encode(URLEncoder.encode(pc.getName(),"UTF-8"),"UTF-8"),Uploader.getDownUrl(ProductClassify.ICON_SUB_DIR)+pc.getIcon(),pc.getOrder()));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}
		}
		return dtos;
	}
	
	@Override
	public List<ParamDto> getHotActivityList(boolean hot) {
		List<ModuleLink> list = new ArrayList<ModuleLink>();
		if(hot){
			list = moduleService.getModuleLinkList(2,1);
		}else{
			list = moduleService.getModuleLinkList(2,0);
		}
		List<ParamDto> dtos = new ArrayList<ParamDto>();
		for(ModuleLink link : list){
			ParamDto dto = new ParamDto(link);
			dto.setValue(Uploader.getDownUrl(ModuleLink.MODULE_LINK_ICON) + dto.getValue());
			dtos.add(dto);
		}
		return dtos;
	}

	@Override
	public List<ProductDto> getHotCarList(Long regionId){
		try {
			List<ProductDto> dtos = productService.getHotCarList(regionId,12);
			return dtos;
		} catch (MelonException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new ArrayList<ProductDto>();
	}

	@Override
	public List<ParamArticle> getNewsInformationList() {
		List<ModuleLink> list = moduleService.getModuleLinkList(4,0);
		List<ParamArticle> dtos = new ArrayList<ParamArticle>();
		for(ModuleLink link : list){
			dtos.add(new ParamArticle(link,get(Integer.valueOf(link.getValue()), Article.class)));
		}
		return dtos;
	}

	@Override
	public List<ParamArticle> getBuyPurchaseList() {
		List<ModuleLink> list = moduleService.getModuleLinkList(5,0);
		List<ParamArticle> dtos = new ArrayList<ParamArticle>();
		for(ModuleLink link : list){
			dtos.add(new ParamArticle(link,get(Integer.valueOf(link.getValue()), Article.class)));
		}
		return dtos;
	}
	
	@Override
	public List<ParamArticle> getCarLeaseList() {
		List<ModuleLink> list = moduleService.getModuleLinkList(6,0);
		List<ParamArticle> dtos = new ArrayList<ParamArticle>();
		for(ModuleLink link : list){
			dtos.add(new ParamArticle(link,get(Integer.valueOf(link.getValue()), Article.class)));
		}
		return dtos;
	}

	@Override
	public Article getArticleDetail(Integer id) {
		Article article = get(id, Article.class);
		return article;
	}

	@Override
	public Pagination<Article> articlePage(Integer page, Integer rp, Integer channel) {
		Pagination<Article> pagination = new Pagination<Article>(rp, page, Article.class);
		pagination.getQueryBuilder().eq("channel.id", channel);
		return queryPageByQueryBuilder(pagination);
	}

	@Override
	public List<City> getCityList() {
		QueryBuilder<Region> qb = createQueryBuilder(Region.class);
		List<Region> list = queryListByQueryBuilder(qb);
		List<City> citys = new ArrayList<City>();
		for(Region r : list){
			citys.add(new City(r.getId(),r.getName()));
		}
		return citys;
	}

	private static String CLASSIFY_LSIT = " SELECT * FROM ML_PRODUCT_CLASSIFY WHERE "; 
	
	@Override
	public List<BaseParam> getSeriesList() {
		StringBuffer sb = new StringBuffer(CLASSIFY_LSIT);
		sb.append(" PARENT IS NULL ");
		List<BaseParam> list = getDao(JdbcDao.class).getJdbcTemplate().query(sb.toString(), new RowMapper<BaseParam>() {
			@Override
			public BaseParam mapRow(ResultSet rs, int arg1) throws SQLException {
				BaseParam param = new BaseParam();
				param.setId(rs.getString("ID"));
				param.setName(rs.getString("NAME"));
				return param;
			}
		});
		return list;
	}

	@Override
	public List<BaseParam> getBrandList(Long manufacturers) {
		StringBuffer sb = new StringBuffer(CLASSIFY_LSIT);
		sb.append(" PARENT = " + manufacturers);
		List<BaseParam> list = getDao(JdbcDao.class).getJdbcTemplate().query(sb.toString(), new RowMapper<BaseParam>() {
			@Override
			public BaseParam mapRow(ResultSet rs, int arg1) throws SQLException {
				BaseParam param = new BaseParam();
				param.setId(rs.getString("ID"));
				param.setName(rs.getString("NAME"));
				return param;
			}
		});
		return list;
	}

	@Override
	public List<BaseParam> getClassifyList(Long brands) {
		StringBuffer sb = new StringBuffer(CLASSIFY_LSIT);
		sb.append(" PARENT = " + brands);
		List<BaseParam> list = getDao(JdbcDao.class).getJdbcTemplate().query(sb.toString(), new RowMapper<BaseParam>() {
			@Override
			public BaseParam mapRow(ResultSet rs, int arg1) throws SQLException {
				BaseParam param = new BaseParam();
				param.setId(rs.getString("ID"));
				param.setName(rs.getString("NAME"));
				return param;
			}
		});
		return list;
	}


}
